﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YXH_Tools_Files.Tools_CSV;
using YXH_Tools_Files.Tools_DirectoryandFile;
using YXH_Tools_Files.Tools_EdgeComputing;
using YXH_Tools_Files.Tools_Error;
using YXH_Tools_Files.Tools_List;

namespace YXH_Tools_Files.Tools_Excute
{
    /// <summary>
    /// 执行合并操作类
    /// </summary>
    public static class Tools_Excute_CSVCombine
    {

        /// <summary>
        ///（专用于边缘采集器） 获得需要处理的日期文件夹列表
        /// </summary>
        /// <param name="originalpath">源数据路径</param>
        /// <param name="combinedpath">指定的合并后的路径</param>
        /// <param name="configuredfolders">指定需要合并的日期文件夹，这是在配置文件读取到的日期数据</param>
        /// <returns></returns>
        public static DirectoryInfo[] YXHGetProcessedFolders(string originalpath, string combinedpath, string[] configuredfolders)
        {
            //获取input路径所有的子文件夹
            var subdirectorieslist = BasicFilesOperation.YXHGetSubDirectories(originalpath);
            //获取目标路径所有的子文件夹
            var subtargetdirectorieslist = BasicFilesOperation.YXHGetSubDirectories(combinedpath);
            //获取指定合并路径下所有已经存在的子文件夹名
            var targetlist = subtargetdirectorieslist.Select(s => s.Name).ToArray();
            DirectoryInfo[] specialdirectory;
            
            //如为null或者为all，则表明需要合并所有的originalpath下的子文件夹，如不为null，则表明需要合并指定的日期文件夹
            if (configuredfolders != null && !configuredfolders.Contains("all"))
            {
                specialdirectory = subdirectorieslist.Where(s => configuredfolders.Contains(s.Name)).ToArray();
            }
            else
            {
                specialdirectory = subdirectorieslist;
            }
            if (targetlist.Length > 0)
            {
                //选择目标路径里没有的文件夹，如有说明之前可能已经合并过了，不需要合并，减少合并时间
                specialdirectory = specialdirectory.Where(s => !targetlist.Contains(s.Name)).ToArray();
                foreach (var s in targetlist)
                {
                    Console.WriteLine("目标路径已有" + s + "的文件夹，不合并此日期文件！");
                }
            }
            return specialdirectory;
        }

        /// <summary>
        /// （专用于边缘采集器）根据合并类型来获得不同的分类好的文件列表，添加了精准里程分割的功能
        /// </summary>
        /// <param name="d">需要分类的文件夹</param>
        /// <param name="combinetype">合并方式：1为按时间合并，0为按txt文件合并，为2则为里程合并</param>
        /// <param name="permileage">里程合并的基准里程</param>
        /// <param name="spdindex">里程合并的指定csv里的车速index</param>
        public static List<MileageClassifyClass> YXHGetClassifyFileListperFolderV2(DirectoryInfo d, string combinetype, int permileage, int spdindex)
        {
            List<MileageClassifyClass> classifylist = new List<MileageClassifyClass>();
            //筛选0kb的csv的数据并转换成txt
            BasicFilesOperation.YXHGetAllextFiles(d.FullName, "*.csv").YXHTransferZeroCsvtoTxt();
            //按时间合并
            if (combinetype == "1")
            {
                //获取每一个子文件夹的所有csv文件，并按文件名排序
                var allfiles = BasicFilesOperation.YXHGetAllextFiles(d.FullName, "*.csv");

                //每半个小时分类汇总成一个总classifylist，每个list里有各自相同时间段的数据
                classifylist = FileInfoOperation_Combination.YXHClassifyFilebyTimeV2(allfiles);
            }
            //按里程来分布
            else if (combinetype == "2")
            {
                //获取每一个子文件夹的所有csv文件，并按文件名排序
                var allfiles = BasicFilesOperation.YXHGetAllextFiles(d.FullName, "*.csv");
                //每多少公里分类汇总成一个总classifylist，每个list里有各自相同里程段的数据
                classifylist = FileInfoOperation_Combination.YXHClassifyFilebyMileagePrecise(allfiles, permileage, spdindex);
            }
            else
            {
                //获取每一个子文件夹的所有txt和csv文件，并按文件名排序
                var allfiles = BasicFilesOperation.YXHGetAllextFiles(d.FullName, "*.*").Where(s => s.Name.ToLower().EndsWith(".csv") || s.Name.ToLower().EndsWith(".txt")).ToArray();
                //每半个小时分类汇总成一个总classifylist，每个list里有各自相同时间段的数据
                classifylist = FileInfoOperation_Combination.YXHClassifyFilebyTxtV2(allfiles);
            }
            return classifylist;
        }

        /// <summary>
        /// （专用于边缘采集器）获得每个分类list合并后的文件路径
        /// </summary>
        /// <param name="d"></param>
        /// <param name="filelist"></param>
        /// <param name="combinedpath"></param>
        /// <param name="combinetype"></param>
        /// <returns></returns>
        public static string YXHGetCombinedFileName(DirectoryInfo d, List<FileInfo> filelist,string combinedpath, string combinetype)
        {
            string combinefilepath = "";
            try
            {
                string filedate = d.Name;
                //获取合并后的指定的日期文件夹路径
                string finalcombinedpath = Path.Combine(combinedpath, filedate);
                if (filelist.Count > 0)
                {
                    //时间模式
                    if (combinetype == "1")
                    {
                        combinefilepath = Path.Combine(finalcombinedpath, filelist[0].YXHGetCombinedFilename());
                    }
                    else
                    {
                        if (filelist.Count > 1)
                        {
                            combinefilepath = Path.Combine(finalcombinedpath, filelist[0].YXHGetCombinedFilenamebyTxt(filelist[filelist.Count - 1]));
                        }
                        else
                        {
                            combinefilepath = Path.Combine(finalcombinedpath, filelist[0].Name);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                string methodName = "";
                // 获取堆栈跟踪信息
                StackTrace stackTrace = new StackTrace(ex);
                // 获取第一个堆栈帧
                StackFrame? stackFrame = stackTrace.GetFrame(0);
                // 获取方法名
                if (stackFrame != null)
                {
                    var s = stackFrame.GetMethod();
                    if (s != null)
                    {
                        methodName = s.Name;
                    }
                }
                LogErrorMessage.getErrormessage(methodName + "方法出现了错误：" + ex.StackTrace);
                Console.WriteLine(methodName + "方法出现了错误：" + ex.StackTrace);
            }
            return combinefilepath;
        }

        /// <summary>
        /// （专用于边缘采集器）执行一个分类好的filelist的合并动作，并输出到指定的csv文件
        /// </summary>
        /// <param name="filelist">一个分类好的filelist</param>
        /// <param name="outputpath">输出到指定的csv文件路径</param>
        public static void YXHExcuteCombinationPerClassifyV2(MileageClassifyClass c, string outputpath)
        {
            try
            {
                
                if (outputpath != "")
                {
                    //处理每个classifylist里的csv文件
                    for (int i = 0; i < c.filelist?.Count; i++)
                    {
                        var csvlist = CSVOperator.YXHCSV2ListV2(c.filelist[i].FullName, i, c.startrowindex, c.endrowindex, c.filelist?.Count);
                        CSVOperator.YXHList2CSV(csvlist, outputpath);
                    }
                }
            }
            catch (Exception ex)
            {
                string methodName="";
                // 获取堆栈跟踪信息
                StackTrace stackTrace = new StackTrace(ex);
                // 获取第一个堆栈帧
                StackFrame? stackFrame = stackTrace.GetFrame(0);
                // 获取方法名
                if (stackFrame != null)
                {
                   var s= stackFrame.GetMethod();
                    if (s != null)
                    {
                        methodName=s.Name;
                    }
                }
                LogErrorMessage.getErrormessage(methodName+"方法出现了错误："+ex.StackTrace);
                Console.WriteLine(methodName + "方法出现了错误：" + ex.StackTrace);
            }

        }


        /// <summary>
        /// （专用于边缘采集器）根据combinetype来执行合并操作，添加了精确里程分布的功能
        /// </summary>
        /// <param name="originalpath"></param>
        /// <param name="combinedpath"></param>
        /// <param name="configuredfolders"></param>
        /// <param name="combinetype"></param>
        /// <param name="permileage"></param>
        /// <param name="spdindex"></param>
        public static async Task<List<string>> YXHExcuteCombinationAllV2(string originalpath, string combinedpath, string[] configuredfolders, string combinetype, int permileage, int spdindex, int threadsnum)
        {
            List<string> list = new List<string>();//专用于输出程序计算过程中的错误信息
            try
            {
                await Task.Run(() =>
                {
                    //先创建输出文件夹
                    Directory.CreateDirectory(combinedpath);
                    //获得需要合并的源数据日期文件夹列表
                    var ds = YXHGetProcessedFolders(originalpath, combinedpath, configuredfolders);
                    if (ds != null)
                    {
                        if(ds.Length > 0)
                        {
                            Stopwatch timer = new Stopwatch();
                            timer.Start();
                            foreach (var d in ds)
                            {
                                Console.WriteLine("开始合并文件夹名为" + d.Name + "的文件，请稍等片刻");
                                //获得分类好的文件列表
                                var classifiedlist = YXHGetClassifyFileListperFolderV2(d, combinetype, permileage, spdindex);
                                Console.WriteLine("已完成" + d.Name + "分类文件列表");

                                //启动多线程
                                ParallelOptions options = new ParallelOptions();
                                options.MaxDegreeOfParallelism = threadsnum;//支持threadsnum个并发执行,控制数量
                                Console.WriteLine($"{d.Name}下共有{classifiedlist.Count}个类别");
                                var r = Parallel.ForEach(classifiedlist, options, c =>
                                {

                                    //获得输出的文件路径
                                    var outputpath = YXHGetCombinedFileName(d, c.filelist, combinedpath, combinetype);

                                    //执行合并csv动作
                                    YXHExcuteCombinationPerClassifyV2(c, outputpath);
                                    if (outputpath != null && outputpath != "")
                                    {
                                        Console.WriteLine($"已完成{outputpath}的文件的合并");
                                    }

                                });

                                //获得输出日期文件夹路径
                                var dateoutputpath = Path.Combine(combinedpath, d.Name);
                                //添加done.txt文件
                                FileInfoOperation_Combination.YXHAddTxt(dateoutputpath);
                                //Console.WriteLine("完成日期为：" + d.Name + "的合并操作共花费了" + timer.Elapsed.TotalMinutes.ToString("0.00") + "分");
                            }
                            timer.Stop();
                            Console.WriteLine($"程序总完成时间为{timer.Elapsed.TotalMinutes.ToString("0.00")}分");
                            list.Add($"程序总完成时间为{timer.Elapsed.TotalMinutes.ToString("0.00")}分");
                        }
                        else
                        {
                            Console.WriteLine("目标路径下已有所有数据，不进行任何操作");
                            list.Add("目标路径下已有所有数据，不进行任何操作");
                        }
                    }
                    else
                    {
                        Console.WriteLine("合并路径有问题，请检查配置文件");
                        list.Add("目标路径有问题，请检查配置文件");
                    }
                });

            }
            catch (Exception ex)
            {
                list.Add("程序出错，请查看错误日志");
                string methodName = "";
                // 获取堆栈跟踪信息
                StackTrace stackTrace = new StackTrace(ex);
                // 获取第一个堆栈帧
                StackFrame? stackFrame = stackTrace.GetFrame(0);
                // 获取方法名
                if (stackFrame != null)
                {
                    var s = stackFrame.GetMethod();
                    if (s != null)
                    {
                        methodName = s.Name;
                    }
                }
                LogErrorMessage.getErrormessage(methodName + "方法出现了错误：" + ex.StackTrace);
                Console.WriteLine(methodName + "方法出现了错误：" + ex.StackTrace);
            }
            return list;
        }

    }
}
